/* Copyright (C) 2009 Christofer Jonsson
 *
 * This file is part of FNM.
 *
 * FNM is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FNM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FNM.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fnm_str.h"
#include "fnm_error.h"
#include "fnm_util.h"

void fnm_str_init(fnm_str_t *str, const char *c_str)
{
   if (c_str != NULL)
   {
      str->len = strlen(c_str);
      str->str = (char*)fnm_util_malloc(sizeof(char) * (str->len + 1));
      strncpy(str->str, c_str, str->len + 1);
   }
}

void fnm_str_destroy(fnm_str_t *str)
{
   if (str->str != NULL)
   {
      fnm_util_free(str->str);
      str->str = NULL;
      str->len = 0;
   }
}

void fnm_str_lower_case(fnm_str_t *str, size_t offset)
{
   const size_t length = str->len;
   size_t i = offset;
   int c = 0;

   while (i < length)
   {
      c = (int)str->str[i] & 0xff;

      if (c >= 65 && c <= 90)
      {
	 str->str[i++] += (char)32;
	 continue;
      }

      /* Assuming UTF-8 */
      if (c == 195 && i + 1 < length)
      {
	 c = (int)str->str[i + 1] & 0xff;
	 
	 if (c == 132 || c == 133 || c == 150 || c == 137)
	    str->str[i + 1] += (char)32;
	 
	 i += 2;
	 continue;
      }

      ++i;
   }
}

void fnm_str_upper_case(fnm_str_t *str, size_t offset)
{
   const size_t length = str->len;
   size_t i = offset;
   int c = 0;

   while (i < length)
   {
      c = (int)str->str[i] & 0xff;

      if (c >= 97 && c <= 122)
      {
	 str->str[i++] -= (char)32;
	 continue;
      }

      /* Assuming UTF-8 */
      if (c == 195 && i + 1 < length)
      {
	 c = (int)str->str[i + 1] & 0xff;
	 
	 if (c == 164 || c == 165 || c == 182 || c == 169)
	    str->str[i + 1] -= (char)32;
	 
	 i += 2;
	 continue;
      }

      ++i;
   }
}

void fnm_str_replace(fnm_str_t *str, 
		     fnm_str_t *old_sub, 
		     fnm_str_t *new_sub,
		     size_t offset)
{
   size_t nrepi = 0;
   size_t new_size = 0;
   char *new_str = NULL;
   size_t i = 0, j = 0, k = 0;
   size_t *repi = (size_t*)fnm_util_malloc(sizeof(size_t) * str->len);

   for (i = offset; i < str->len;)
   {
      /* Find the positions of the old substrings */
      if (strncmp(str->str + i, old_sub->str, old_sub->len) == 0)
      {
	 repi[nrepi++] = i;
	 i += old_sub->len;
	 continue;
      }
      
      ++i;
   }

   /* Nothing to replace */
   if (nrepi == 0)
   {
      fnm_util_free(repi);
      return;
   }
   
   /* Create the new string */
   new_size = str->len + 1 + (new_sub->len - old_sub->len) * nrepi;
   new_str = (char*)fnm_util_malloc(sizeof(char) * new_size);

   for (i = 0, j = 0, k = 0; k < new_size - 1;)
   {
      if (j < nrepi && i == repi[j])
      {
	 /* Replace the old substring with the new substring */
	 strncpy(new_str + k, new_sub->str, new_sub->len);
	 i += old_sub->len;
	 k += new_sub->len;
	 ++j;     
	 continue;
      }

      new_str[k++] = str->str[i++];      
   }

   new_str[new_size - 1] = '\0';
   
   /* Clean up */
   fnm_util_free(str->str);
   fnm_util_free(repi);

   str->str = new_str;
   str->len = new_size - 1;
}
